/*
 * @Date: 2022-04-17 23:44:49
 * @LastEditTime: 2022-04-18 15:04:35
 * @brief: 服务端逻辑代码
 */
#include <pthread.h>

#include "messageClass.hpp"
#include "linuxUDPsocket.hpp"
#include "userClass.hpp"

linuxSocket Sock;
Message Mes;
USERMODEL UsersModel;
userInfo User;
pthread_t tid[2]; // 创建两个用于下载和上传的线程
struct sockaddr_in *logined_addr = new sockaddr_in[10]; // 已登录的用户地址集
char logined_username[10][MAX_USERNAME_LENGTH];
int onlineNum = 0; // 目前登陆的人数

socklen_t clnt_addr_size = sizeof(sockaddr_in);

char resvBuffer[max_message_length] = {0};
char sendBuffer[max_message_length] = {0};

int send(sockaddr_in *clnt_addr) {
  // Mes.set_data(buffer);
  Sock.Send(Mes.data(), max_message_length, clnt_addr);
  return 1;
}

int resv(sockaddr_in *clnt_addr) {
  memset(resvBuffer, 0, max_message_length);
  Sock.Resv(resvBuffer, clnt_addr, &clnt_addr_size);
  Mes.set_data(resvBuffer);
  return 1;
}
// 用于客户端声明停止接受信息
int exit() {
  cout << "exit" << endl;
  std::memcpy(&User, Mes.body(), sizeof(userInfo));
  StatusType resType = UsersModel.login(User.username, User.password);
  cout << resType << endl;
  Mes.setMessage(Mes.head().type, (char *)&SERVER_NAME, User.username, (char *)&User, sizeof(userInfo), resType);
  send(&logined_addr[onlineNum]);
  if (resType == SUCCESS) {
    for(int i = 0; i < onlineNum; i++) {
      if (logined_addr[i].sin_addr.s_addr == logined_addr[onlineNum].sin_addr.s_addr &&
      logined_addr[i].sin_port == logined_addr[onlineNum].sin_port) {
        std::memcpy(logined_username + i * sizeof(User.username), logined_username + (onlineNum - 1) * MAX_USERNAME_LENGTH, MAX_USERNAME_LENGTH);
        logined_addr[i].sin_addr.s_addr = logined_addr[onlineNum - 1].sin_addr.s_addr;
        logined_addr[i].sin_family = logined_addr[onlineNum - 1].sin_family;
        logined_addr[i].sin_port = logined_addr[onlineNum - 1].sin_port;
        printf("iP: %s, port: %d\n", inet_ntoa(logined_addr[i].sin_addr), ntohs(logined_addr[i].sin_port));
        printf("iP: %s, port: %d\n", inet_ntoa(logined_addr[onlineNum - 1].sin_addr), ntohs(logined_addr[onlineNum - 1].sin_port));
        onlineNum--;
        break;
      }
    }
  }
  return 1;
}

// TODO: 需要补充退出登录的逻辑
int login() {
  cout << "logging" << endl;
  std::memcpy(&User, Mes.body(), sizeof(userInfo));
  StatusType resType = UsersModel.login(User.username, User.password);
  cout << resType << endl;
  Mes.setMessage(Mes.head().type, (char *)&SERVER_NAME, User.username, (char *)&User, sizeof(userInfo), resType);
  printf("iP: %s, port: %d\n", inet_ntoa(logined_addr[onlineNum].sin_addr), ntohs(logined_addr[onlineNum].sin_port));
  send(&logined_addr[onlineNum]);
  if (resType == SUCCESS) {
    std::memcpy(logined_username + onlineNum * sizeof(User.username), User.username, MAX_USERNAME_LENGTH);
    onlineNum++;
  }
  return 1;
}

int broadcast() {
  cout << "chatting" << endl;
  cout << Mes.body() << endl;
  Mes.transfrom(Mes.head().source, (char *)&BROADCAST, SUCCESS);
  for (int i = 0; i < onlineNum; i++) {
    // if (
    //   logined_addr[i].sin_addr.s_addr != logined_addr[onlineNum].sin_addr.s_addr ||
    //   logined_addr[i].sin_port != logined_addr[onlineNum].sin_port
    // ) {
      
    // }
    send(&logined_addr[i]);
  }
  return 1;
}

void *uploadFile(void *fm){
    //先检查文件是否存在
    // char const *filename = "./send.exe";  //文件名
    FILE *fp = (FILE *)fm;  //以二进制方式打开文件
    if(fp == NULL){
        printf("Cannot open file, press any key to exit!\n");
        return 0;
    }
    int servSock = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in servAddr;
    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = PF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(25525);
    bind(servSock, (sockaddr*)&servAddr, sizeof(servAddr));
    listen(servSock, 20);
    sockaddr_in clntAddr;
    socklen_t nSize = sizeof(sockaddr_in);
    int clntSock = accept(servSock, (struct sockaddr*)&clntAddr, &nSize);
    //循环发送数据，直到文件结尾
    char buffer[512] = {0};  //缓冲区
    int nCount;
    // while( (nCount = fread(buffer, 1, 512, fp)) > 0 ){
    //   write(clntSock, buffer, nCount);
    // }
    while( (nCount = read(clntSock, buffer, 512)) > 0 ){
        fwrite(buffer, nCount, 1, fp);
    }
    shutdown(clntSock, SHUT_WR);  //文件读取完毕，断开输出流，向客户端发送FIN包
    read(clntSock, buffer, 512);  //阻塞，等待客户端接收完毕
    fclose(fp);
    close(clntSock);
    close(servSock);
    return fp;
};

int upload() {
  cout << "uploading!!" << endl;
  char filename[20];
  std::memcpy(filename, Mes.body(), 20);
  cout << "filename: " << filename << endl;
  FILE *fp = fopen(filename, "wb");  //以二进制方式打开文件
  Mes.setMessage(Mes.head().type, (char *)&SERVER_NAME, User.username, (char *)&filename, 20, SUCCESS);
  send(&logined_addr[onlineNum]);
  int err = pthread_create(&(tid[1]), NULL, &uploadFile, (void *)fp);
  return 1;
}

void *downloadFile(void *fm){
    //先检查文件是否存在
    // char const *filename = "./send.exe";  //文件名
    FILE *fp = (FILE *)fm;  //以二进制方式打开文件
    if(fp == NULL){
        printf("Cannot open file, press any key to exit!\n");
        return 0;
    }
    int servSock = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in servAddr;
    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = PF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(25525);
    bind(servSock, (sockaddr*)&servAddr, sizeof(servAddr));
    listen(servSock, 20);
    sockaddr_in clntAddr;
    socklen_t nSize = sizeof(sockaddr_in);
    int clntSock = accept(servSock, (struct sockaddr*)&clntAddr, &nSize);
    //循环发送数据，直到文件结尾
    char buffer[512] = {0};  //缓冲区
    int nCount;
    while( (nCount = fread(buffer, 1, 512, fp)) > 0 ){
      write(clntSock, buffer, nCount);
    }
    shutdown(clntSock, SHUT_WR);  //文件读取完毕，断开输出流，向客户端发送FIN包
    read(clntSock, buffer, 512);  //阻塞，等待客户端接收完毕
    fclose(fp);
    close(clntSock);
    close(servSock);
    return fp;
};

int download() {
  char filename[20];
  std::memcpy(filename, Mes.body(), 20);
  FILE *fp = fopen(filename, "rb");  //以二进制方式打开文件
  if(fp == NULL){
      Mes.setMessage(Mes.head().type, (char *)&SERVER_NAME, User.username, (char *)&filename, 20, NOTFOUND);
      send(&logined_addr[onlineNum]);
      return 0;
  } else {
    cout << filename << endl;
    Mes.setMessage(Mes.head().type, (char *)&SERVER_NAME, User.username, (char *)&filename, 20, SUCCESS);
    send(&logined_addr[onlineNum]);
    int err = pthread_create(&(tid[0]), NULL, &downloadFile, (void *)fp);
    return 1;
  }
}

int main(){
  while(1) {
    printf(".");
    fflush(stdout);
    sleep(1);
    resv(&logined_addr[onlineNum]);
    Mes.print_header();
    switch(Mes.head().type) {
      case EXIT:
        exit();
        break;
      case MT_USERINFO:
        login();
        break;
      case MT_CHATINFO:
        broadcast();
        break;
      case MT_FILE_UPLOAD:
        upload();
        break;
      case MT_FILE_DOWNLOAD:
        download();
        break;
      default:
        cout << "无效" << endl;
    }
    // Mes.set_data(resvBuffer);
    // send(&clnt_addr);
  }
  delete logined_addr;
  return 0;
}